# -*- coding: utf-8 -*-
# standard library imports
import logging
# related third party imports
import webapp2
from google.appengine.ext import ndb
from google.appengine.api import users, memcache, search
from google.appengine.api.images import get_serving_url
from webapp2_extras import jinja2, sessions, json
# local application/library specific imports
from lib import utils
from application import models


class BaseHandler(webapp2.RequestHandler):

    @webapp2.cached_property
    def settings(self):
        return models.AppSetting.query().get()

    @webapp2.cached_property
    def session_store(self):
        return sessions.get_store(request=self.request)

    @webapp2.cached_property
    def session(self):
        # Returns a session using the default cookie key.
        return self.session_store.get_session()

    @webapp2.cached_property
    def user(self):
        return users.get_current_user()

    @webapp2.cached_property
    def user_id(self):
        return self.user.user_id() if self.user else None

    # @webapp2.cached_property
    def get_user_info(self, mem=False):
        if self.user:
            if not mem:
                user_info = models.User.get_by_id(self.user_id)
                if user_info:
                    return user_info
                else:
                    user_info = models.User.get_by_id("btd:%s" % self.user.email())
                    if user_info:
                        return user_info
            else:
                user_info = memcache.get("app:ajani:ui%s" % self.user_id)
                if not user_info:
                    user_info = memcache.get("app:ajani:uibtd:%s" % self.user.email())
                    if not user_info:
                        user_info = self.get_user_info()
                        if not user_info:
                            return None
                        img = get_serving_url(user_info.img, size=100) if user_info.img else None
                        if img:
                            img = "<img src='%s'/>" % img
                        display_name = user_info.display if user_info.display else self.user.nickname()
                        mem = dict(
                            id=user_info.key.id(),
                            display=display_name,
                            name=user_info.name,
                            email=user_info.email,
                            country=user_info.country,
                            gender=user_info.gender,
                            bio=user_info.bio,
                            address=user_info.address,
                            phone=user_info.phone,
                            dob_y=user_info.dob.year if user_info.dob else None,
                            dob_m=user_info.dob.month - 1 if user_info.dob else None,
                            dob_d=user_info.dob.day if user_info.dob else None,
                            dob=user_info.dob.strftime("%d %B %Y") if user_info.dob else None,
                            img=img
                        )
                        memcache.add('app:ajani:ui%s' % user_info.key.id(), json.encode(mem))
                        return mem
                return json.decode(user_info)
        return None

    @webapp2.cached_property
    def admin(self):
        user_info = self.get_user_info()
        if user_info:
            try:
                adm_key = ndb.Key(models.Admin, "adm:%s" % user_info.key.id(), parent=user_info.key)
                adm = models.Admin.query(ancestor=adm_key).get()
                return adm
            except Exception, e:
                logging.error(e)
        return None

    def send_message(self, to, sender=None, title="", content="", item=None):
        try:
            message = models.Message()
            message.receiver = ndb.Key(models.User, to)
            if sender:
                message.sender = ndb.Key(models.User, sender)
            message.title = title
            message.content = dict(raw=content, strp=utils.remove_tags(content))
            if item:
                message.item = ndb.Key(models.Item, item)
            message.put()

            m_m = memcache.get('app:itbuy:m%s' % to)
            if not m_m:
                memcache.add('app:itbuy:m%s' % to, utils.model_encode([message]))
            else:
                m_m = json.decode(m_m)
                m_m.append(message)
                memcache.set('app:itbuy:m%s' % to, utils.model_encode(m_m))
            return True
        except Exception, e:
            logging.error(e)
            return False

    def create_item_document(self, key, title, desc, price):
        doc = search.Document(
                doc_id=key,
                fields=[search.TextField(name="title", value=title),
                        search.HtmlField(name="desc", value=desc),
                        search.NumberField(name="price", value=price)],
                language='en')
        self.index_document('item', doc)

    def search_item(self, query_string):
        try:
            q_string = query_string
            if query_string.isdigit():
                q_string = "title:%s OR price = %s" % (query_string, query_string)
            options = search.QueryOptions(limit=10)
            query = search.Query(query_string=q_string, options=options)
            index = search.Index(name='item')
            result = index.search(query)
        except Exception, e:
            logging.error(e)
            result = None
        finally:
            return result

    def index_document(self, name, document):
        try:
            search.Index(name=name).put(document)
        except Exception, e:
            logging.error(e)


class BaseWebHandler(BaseHandler):
    """
        BaseWebHandler for request that require
        html response. The response comes from
        rendered jinja2 templates.
    """

    def dispatch(self):
        """
            Get a session store for this request.
        """
        # self.session_store = sessions.get_store(request=self.request)

        try:
            # csrf protection
            if self.request.method != "GET" and not self.request.path.startswith('/tasks'):
                token_sess = self.session.get('XSRF-TOKEN')
                token_cook = self.request.cookies.get('XSRF-TOKEN')
                token_head = self.request.headers['X-XSRF-TOKEN']
                if not token_sess or not token_cook:
                    self.abort(403)
                if (token_head != token_sess) and (token_head != token_cook):
                    self.abort(403)

            # Dispatch the request.
            webapp2.RequestHandler.dispatch(self)
        finally:
            # Save all sessions.
            self.session_store.save_sessions(self.response)

    @webapp2.cached_property
    def jinja2(self):
        """
            Returns a Jinja2 renderer cached in the app registry.
        """
        return jinja2.get_jinja2(factory=jinja2_factory, app=self.app)

    def render_response(self, _template, **context):
        """
            Renders a template and writes the result to the response.
        """
        # context.update({
        #     'user_id': self.user_id,
        #     'username': self.username,
        #     'email': self.email,
        #     'admin': self.admin,
        #     'path': self.request.path,
        # })
        rv = self.jinja2.render_template(_template, **context)
        self.response.write(rv)


class BaseApiHandler(BaseHandler):
    """
        BaseApiHandler for API request.
        Response will always be json encoded.
    """

    def dispatch(self):
        """
            Get a session store for this request.
        """
        # logging.warn(self.session.get('XSRF-TOKEN'))
        if not self.request.headers['X-Requested-With']:
            logging.warn('Illegal Request')
            self.abort(405)
        if self.request.headers['X-Requested-With'] != 'XMLHttpRequest':
            logging.warn('Illegal Request')
            self.abort(405)
        # self.session_store = sessions.get_store(request=self.request)

        try:
            # csrf protection
            if self.request.method != "GET" and not self.request.path.startswith('/tasks'):
                token_sess = self.session.get('XSRF-TOKEN')
                token_cook = self.request.cookies.get('XSRF-TOKEN')
                token_head = self.request.headers['X-XSRF-TOKEN']
                # logging.warn(token_sess)
                # logging.warn(token_cook)
                # logging.warn(token_head)
                if not token_sess or not token_cook:
                    logging.warn('CSRF Possible attack 1')
                    self.abort(403)
                if (token_head != token_sess) and (token_head != token_cook):
                    logging.warn('CSRF Possible attack')
                    self.abort(403)

            # Dispatch the request.
            webapp2.RequestHandler.dispatch(self)
        finally:
            # Save all sessions.
            self.session_store.save_sessions(self.response)

    def out(self, resp):
        """
            Out Response with JSON Vulnerability Protection
        """
        if isinstance(resp, str):
            _out = ")]}',\n%s" % resp
        else:
            _out = ")]}',\n%s" % utils.model_encode(resp)

        if 'application/json' in self.request.headers.get('Accept'):
            self.response.headers['Content-Type'] = 'application/json'
        self.response.out.write(_out)


def generate_csrf_token():
    session = sessions.get_store().get_session()
    # if 'XSRF-TOKEN' not in session:
    #     session['XSRF-TOKEN'] = utils.random_string()
    #     return "blah"
    return session['XSRF-TOKEN']


def jinja2_factory(app):
    j = jinja2.Jinja2(app)
    j.environment.filters.update({
        # Set filters.
        # ...
    })
    j.environment.globals.update({
        # Set global variables.
        'csrf_token': generate_csrf_token,
        'uri_for': webapp2.uri_for,
        'getattr': getattr,
        'str': str
    })
    j.environment.tests.update({
        # Set test.
        # ...
    })
    return j
